package gemini.castor.ui.client.mvp.container;

import gemini.castor.ui.client.mvp.event.LocalEventBus;
import gemini.castor.ui.client.mvp.single.CastorWidgetPresenter;
import gemini.castor.ui.client.utils.PlaceConstants.LayoutPosition;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import ch.elca.gwt.mvp.client.EventBus;
import ch.elca.gwt.mvp.client.PresenterRevealedEvent;
import ch.elca.gwt.mvp.client.PresenterRevealedHandler;
import ch.elca.gwt.mvp.client.place.Place;
import ch.elca.gwt.mvp.client.widget.WidgetPresenter;


/**
 * This class provides support for widgets that contain other widgets. It will
 * listen for {@link PresenterRevealedEvent}s and reveal itself if the source
 * was a direct child of this presenter.
 */
public abstract class CastorWidgetContainerPresenter<T extends CastorWidgetContainerDisplay> extends WidgetPresenter<T> {

    private final List<CastorWidgetPresenter<?>> presenters;

    private CastorWidgetPresenter<?> currentPresenter;
    private Place defaultPlace;
     
    private final LocalEventBus localEventBus = new LocalEventBus(this);

    public CastorWidgetContainerPresenter( T display, EventBus eventBus,
    		CastorWidgetPresenter<?>... presenters ) {
        super( display, eventBus );
        this.presenters = new ArrayList<CastorWidgetPresenter<?>>();
        Collections.addAll( this.presenters, presenters );
		
        // set first presenter as default place
        if (!this.presenters.isEmpty()) {
			setDefaultPlace(this.presenters.get(0).getPlace());
		}
    }
    
	public boolean isDefaultPlace() {
		boolean result = false;
		
		result = currentPresenter != null
				&& currentPresenter.getPlace().equals(getDefaultPlace());
		
		return result;
	}
	
	protected void showDefaultPresenter() {
		unbindCurrentPresenter();

		for (CastorWidgetPresenter<?> presenter : presenters) {
			if (presenter.getPlace().equals(getDefaultPlace())) {
				currentPresenter = presenter;
				break;
			}
		}

		if (!currentPresenter.isBound()) {
			currentPresenter.bind();
		}

		refreshDisplay();

		currentPresenter.setLocalEventBus(localEventBus);

		display.showWidget(currentPresenter.getDisplay().asWidget());
	}

    /**
     * Adds the presenter, if the current presenter is unbound.
     * 
     * @param presenter
     *            The presenter to add.
     * @return If added, returns <code>true</code>.
     */
    protected boolean addPresenter( CastorWidgetPresenter<?> presenter ) {
        if ( !isBound() ) {
        	
        	// if this is the first presenter in container, set as default place
			if (presenters.isEmpty()) {
				setDefaultPlace(presenter.getPlace());
			}
            presenters.add( presenter );
            return true;
        }
        return false;
    }

    @Override
    protected void onBind() {
        eventBus.addHandler( PresenterRevealedEvent.getType(), new PresenterRevealedHandler() {
            public void onPresenterRevealed( PresenterRevealedEvent event ) {
                if ( presenters.contains( event.getPresenter() ) ) {
                    showPresenter( (gemini.castor.ui.client.mvp.single.CastorWidgetPresenter<?> ) event.getPresenter(), false );
                    revealDisplay();
                }
            }
        } );
    }

    @Override
    protected void onUnbind() {
    	unbindCurrentPresenter();
    }
    
    private void unbindCurrentPresenter(){
    	if(currentPresenter != null && currentPresenter.isBound()){
    		currentPresenter.unbind();
    	}
    }

    protected CastorWidgetPresenter<?> getCurrentPresenter() {
        return currentPresenter;
    }

    protected int indexOf(CastorWidgetPresenter<?> presenter ) {
        return presenters.indexOf( presenter );
    }

	protected void showPresenter(CastorWidgetPresenter<?> presenter, Object inputObject) {
		if (indexOf(presenter) >= 0) {
			unbindCurrentPresenter();
			
			currentPresenter = presenter;

			if (inputObject != null) {
				currentPresenter.setInputObject(inputObject);
			}
			
			if (!currentPresenter.isBound()) {
				currentPresenter.bind();
			}
			currentPresenter.setLocalEventBus(localEventBus);
			
			refreshDisplay();
				
			display.showWidget(currentPresenter.getDisplay().asWidget());
		}
	}
	
	protected void showPresenter(CastorWidgetPresenter<?> presenter, Object inputObject, boolean refreshDisplay) {
		if (indexOf(presenter) >= 0) {
			unbindCurrentPresenter();
			
			currentPresenter = presenter;

			if (inputObject != null) {
				currentPresenter.setInputObject(inputObject);
			}
			
			if (!currentPresenter.isBound()) {
				currentPresenter.bind();
			}
			currentPresenter.setLocalEventBus(localEventBus);
			
			if(refreshDisplay){
				refreshDisplay();
			}
				
			display.showWidget(currentPresenter.getDisplay().asWidget());
		}
	}
	
	protected void showPresenter(CastorWidgetPresenter<?> presenter, boolean refreshDisplay) {
		if (indexOf(presenter) >= 0) {
			unbindCurrentPresenter();
			
			currentPresenter = presenter;

			if (!currentPresenter.isBound()) {
				currentPresenter.bind();
			}
			currentPresenter.setLocalEventBus(localEventBus);
			
			if(refreshDisplay){
				refreshDisplay();
			}
				
			display.showWidget(currentPresenter.getDisplay().asWidget());
		}
	}
	
	protected void showPresenter(CastorWidgetPresenter<?> presenter) {
		if (indexOf(presenter) >= 0) {
			unbindCurrentPresenter();
			
			currentPresenter = presenter;

			if (!currentPresenter.isBound()) {
				currentPresenter.bind();
			}
			currentPresenter.setLocalEventBus(localEventBus);
							
			display.showWidget(currentPresenter.getDisplay().asWidget());
		}
	}

	public void refreshDisplay() {
		if (currentPresenter != null && currentPresenter.isBound()) {
			currentPresenter.refreshDisplay();
		}
	}

	public LocalEventBus getLocalEventBus() {
		return localEventBus;
	}

	public void setDefaultPlace(Place defaultPlace) {
		this.defaultPlace = defaultPlace;
	}

	public Place getDefaultPlace() {
		return defaultPlace;
	}

	public LayoutPosition getPosition() {
		return LayoutPosition.CONTENT;
	}
	
	public void setInputObject(Object object){
		
	}
}
